package fxLib
{
	import fl.motion.Color;
	import fl.transitions.Tween;
	import fl.transitions.TweenEvent;
	import fl.transitions.easing.*;
	
	import flash.display.MovieClip;
	import flash.filters.GlowFilter;
	
	public class FXFlash
	{
		private static const nFLASH_DURATION:Number           = 1500 / 1000;
		private static const nFADEIN_PORTION:Number           = 0.1;
		private static const nGLOW_SCALE:Number               = 40;
		private static const nGLOW_STRENGTH:Number            = 2;
		private static const nGLOW_QUALITY:Number             = 2;
		
		// set defaults for gettersetters
		private var mnGlowScale:Number                        = nGLOW_SCALE;
		private var mnFlashDuration:Number                    = nFLASH_DURATION;
		
		private var mcFlashObject:MovieClip;
		
		private var mcGlowFilter:GlowFilter;
		private var mcGlowFadeXTween:Tween;
		private var mcGlowFadeYTween:Tween;
		private var mcGlowFadeAlphaTween:Tween;
		
		private var mcBrightnessTween:Tween;
		
		private var mbGlowXDone:Boolean;
		private var mbGlowYDone:Boolean;
		private var mbGlowAlphaDone:Boolean;
		private var mbBrightnessDone:Boolean;
		
		private var mcPhase:int                                = 0;
		
		// constructor
		// call this function to make an object white-flash
		public function FXFlash( acMCtoFlash:MovieClip, acParams:Object = null )
		{
			// accept parameters if given, in Object format
			if (acParams != null)
			{
				if ( !isNaN( acParams.glowScale ) )
					mnGlowScale         = acParams.glowScale;
				if ( !isNaN( acParams.flashDuration ) )
					mnFlashDuration     = acParams.flashDuration;
			}
			
			mcFlashObject               = acMCtoFlash;
			
			mcGlowFilter                = new GlowFilter( 0xFFFFFF, 1.0, mnGlowScale, mnGlowScale, nGLOW_STRENGTH, nGLOW_QUALITY, false, false );
			mcGlowFadeXTween            = new Tween( mcGlowFilter, "blurX", Regular.easeIn, 1, mnGlowScale, mnFlashDuration * nFADEIN_PORTION, true );
			mcGlowFadeYTween            = new Tween( mcGlowFilter, "blurY", Regular.easeIn, 1, mnGlowScale, mnFlashDuration * nFADEIN_PORTION, true );
			mcGlowFadeAlphaTween        = new Tween( mcGlowFilter, "alpha", Regular.easeIn, 0.0, 1.0, mnFlashDuration * nFADEIN_PORTION, true );
			mcGlowFadeXTween.start();
			mcGlowFadeYTween.start();
			mcGlowFadeAlphaTween.start();
			
			mcGlowFadeXTween.addEventListener( TweenEvent.MOTION_CHANGE, onMotionChanged );
			mcGlowFadeXTween.addEventListener( TweenEvent.MOTION_FINISH, onMotionFinished );
			
			mcPhase = 1;
			
			startBrightness();
		}
		
		private function destroy():void
		{
			mcGlowFadeXTween            = null;
			mcGlowFadeYTween            = null;
			mcGlowFadeAlphaTween        = null;
			mcBrightnessTween           = null;
			mcGlowFilter                = null;
			
			mcFlashObject.filters       = []; // WARNING! This will only support one filter on the object at a time. Not flexible.
			//removeGlowFilter();
			
			mcFlashObject               = null;
			
			//trace("[FXFlash destroy]");
		}
		
		// allow programmer to stop playback of effect if required!
		public function stop():void
		{
			switch (mcPhase)
			{
				case 1: // fade up
					mcGlowFadeXTween.removeEventListener( TweenEvent.MOTION_CHANGE, onMotionChanged );
					mcGlowFadeXTween.removeEventListener( TweenEvent.MOTION_FINISH, onMotionFinished );
					
					mcGlowFadeXTween.stop();
					mcGlowFadeYTween.stop();
					mcGlowFadeAlphaTween.stop();
					
					mcBrightnessTween.removeEventListener( TweenEvent.MOTION_FINISH, brightnessInFinished );
					mcBrightnessTween.stop();
					
					updateBrightness = 0;
					break;
				
				case 2: // fade down
					mcGlowFadeXTween.removeEventListener( TweenEvent.MOTION_CHANGE, onMotionChanged );
					mcGlowFadeXTween.removeEventListener( TweenEvent.MOTION_FINISH, onGlowXFinished );
					mcGlowFadeYTween.removeEventListener( TweenEvent.MOTION_FINISH, onGlowYFinished );
					mcGlowFadeAlphaTween.removeEventListener( TweenEvent.MOTION_FINISH, onGlowAlphaFinished );
					
					mcGlowFadeXTween.stop();
					mcGlowFadeYTween.stop();
					mcGlowFadeAlphaTween.stop();
					
					mcBrightnessTween.removeEventListener( TweenEvent.MOTION_FINISH, brightnessOutFinished );
					mcBrightnessTween.stop();
					
					updateBrightness = 0;
					break;
				
				case 3: // after destroy
					// ignore
					break;
				
				default:
					//trace("[FXFlash stop] Unexpected this is.");
			}
			
			destroy();
		}
		
		private function removeGlowFilter():void
		{
			if (mcFlashObject != null)
			{
				var nGlowAt:int = mcFlashObject.filters.indexOf( mcGlowFilter );
				
				if (nGlowAt > -1)
				{
					mcFlashObject.filters.splice( nGlowAt, 1 );
				}
			}
		}
		
		private function addGlowFilter():void
		{
			if (mcGlowFilter != null)
			{
				mcFlashObject.filters.push( mcGlowFilter );
			}
		}
		
		//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		// keep updating the filter...
		public function onMotionChanged( event:TweenEvent ):void
		{ 
			mcFlashObject.filters = [mcGlowFilter]; // WARNING! This will only support one filter on the object at a time. Not flexible.
			
			// didn't work:
			//removeGlowFilter();
			//addGlowFilter();
		}
		
		// tween is midway, start downward...
		public function onMotionFinished( event:TweenEvent ):void
		{
			event.target.addEventListener( TweenEvent.MOTION_CHANGE, onMotionChanged );
			event.target.removeEventListener( TweenEvent.MOTION_FINISH, onMotionFinished );
			
			// start fade down...
			mcGlowFadeXTween            = new Tween( mcGlowFilter, "blurX", Regular.easeOut, mnGlowScale, 1, mnFlashDuration - (nFADEIN_PORTION * mnFlashDuration), true );
			mcGlowFadeYTween            = new Tween( mcGlowFilter, "blurY", Regular.easeOut, mnGlowScale, 1, mnFlashDuration - (nFADEIN_PORTION * mnFlashDuration), true );
			mcGlowFadeAlphaTween        = new Tween( mcGlowFilter, "alpha", Regular.easeOut, 1.0, 0.0, mnFlashDuration - (nFADEIN_PORTION * mnFlashDuration), true );
			mcGlowFadeXTween.start();
			mcGlowFadeYTween.start();
			mcGlowFadeAlphaTween.start();
			
			mcGlowFadeXTween.addEventListener( TweenEvent.MOTION_CHANGE, onMotionChanged );
			mcGlowFadeXTween.addEventListener( TweenEvent.MOTION_FINISH, onGlowXFinished );
			mcGlowFadeYTween.addEventListener( TweenEvent.MOTION_FINISH, onGlowYFinished );
			mcGlowFadeAlphaTween.addEventListener( TweenEvent.MOTION_FINISH, onGlowAlphaFinished );
			
			mcPhase = 2;
		}
		
		// filter's done, kill it...
		public function onGlowXFinished( event:TweenEvent ):void
		{
			mbGlowXDone = true;
			event.target.removeEventListener( TweenEvent.MOTION_FINISH, onGlowXFinished );
			
			conditionalDestroy();
		}
		
		public function onGlowYFinished( event:TweenEvent ):void
		{
			mbGlowYDone = true;
			event.target.removeEventListener( TweenEvent.MOTION_FINISH, onGlowYFinished );
			
			conditionalDestroy();
		}
		
		public function onGlowAlphaFinished( event:TweenEvent ):void
		{
			mbGlowAlphaDone = true;
			event.target.removeEventListener( TweenEvent.MOTION_FINISH, onGlowAlphaFinished );
			
			conditionalDestroy();
		}
		
		// only destroy once all tweens have finished
		private function conditionalDestroy():void
		{
			if (mbGlowXDone && mbGlowYDone && mbGlowAlphaDone && mbBrightnessDone)
			{
				mcGlowFadeXTween.removeEventListener( TweenEvent.MOTION_CHANGE, onMotionChanged );
				
				destroy();
				mcPhase = 3;
			}
		}
		
		private function startBrightness():void
		{
			mcBrightnessTween = new Tween( this, "updateBrightness", Regular.easeIn, 0, 1, nFADEIN_PORTION * mnFlashDuration, true );
			mcBrightnessTween.addEventListener( TweenEvent.MOTION_FINISH, brightnessInFinished );
		}
		
		private function brightnessInFinished( e:TweenEvent ):void 
		{
			updateBrightness = 1;
			mcBrightnessTween.removeEventListener( TweenEvent.MOTION_FINISH, brightnessInFinished );
			mcBrightnessTween = new Tween( this, "updateBrightness", Regular.easeOut, 1, 0, mnFlashDuration - (nFADEIN_PORTION * mnFlashDuration), true );
			mcBrightnessTween.addEventListener( TweenEvent.MOTION_FINISH, brightnessOutFinished );
		}
		
		private function brightnessOutFinished( e:TweenEvent ):void 
		{
			updateBrightness = 0;
			mbBrightnessDone = true;
			
			mcBrightnessTween.removeEventListener( TweenEvent.MOTION_FINISH, brightnessOutFinished );
			
			conditionalDestroy();
		}
		
		// set the brightness
		public function set updateBrightness( newValue:Number ):void
		{
			var color:Color = new Color();
			color.brightness = newValue;
			
			mcFlashObject.transform.colorTransform = color; 		
		}
		
		//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
		// getters and setters for all properties
		
		public function set glowScale( anGlowScale:Number ):void
		{
			mnGlowScale = anGlowScale;
		}
		
		public function get glowScale():Number
		{
			return mnGlowScale;
		}
		
		public function set flashDuration( anFlashDuration:Number ):void
		{
			mnFlashDuration = anFlashDuration;
		}
		
		public function get flashDuration():Number
		{
			return mnFlashDuration;
		}
		
		//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
		
	}
}